<template>
  <div>
    <a-row
      class="naviBar"
      type="flex"
      style="flex-wrap: nowrap;"
      align="middle"
    >
      <a-icon
        :class="{ icon: true, disabled: pathStackIndex === 0 }"
        @click="goBack"
        type="arrow-left"
      />
      <a-icon
        :class="{
          icon: true,
          disabled: pathStackIndex === pathStack.length - 1,
        }"
        @click="goForward"
        type="arrow-right"
      />
      <a-icon
        :class="{ icon: true, disabled: upperPath === path }"
        @click="gotoUpperPath"
        type="arrow-up"
      />
      <navi-input
        class="pathInput"
        :value="path"
        @pressEnter="handlePathInput"
        @clickPath="clickPath"
      />
      <a-icon :class="{ icon: true }" @click="refresh" type="reload" />
      <a-input
        class="searchInput"
        v-model="searchKey"
        placeholder="请输入搜索内容"
      >
        <a-icon slot="addonBefore" type="search" />
      </a-input>
    </a-row>
    <div class="content">
      <a-table
        :columns="columns"
        :data-source="filterList"
        rowKey="name"
        :loading="$apollo.queries.list.loading"
        :pagination="false"
        :scroll="{ y: tableContentHeight }"
      >
        <a-row
          slot="name"
          slot-scope="text, record"
          type="flex"
          align="middle"
          :class="{ filename: true, hidden: record.isHidden }"
          style="flex-wrap: nowrap;"
        >
          <img v-if="record.icon" class="icon" :src="record.icon" />
          <a @dblclick="openPath(record)">{{ text }}</a>
        </a-row>
        <span slot="type" slot-scope="text">{{ formatType(text) }}</span>
        <span slot="size" slot-scope="text, record">{{
          record.type === 'dir' ? '' : formatSize(text)
        }}</span>
        <span slot="mtime" slot-scope="text">{{ formatTime(text) }}</span>
        <span slot="atime" slot-scope="text">{{ formatTime(text) }}</span>
      </a-table>
    </div>
  </div>
</template>

<script>
import Vue from 'vue'
import gql from 'graphql-tag'
import moment from 'moment'
import { debounce } from 'lodash'
import formatIO from 'format-io'
import os from 'os'
const showError = debounce((err) => {
  if (process.client) Vue.prototype.$message.error(err.message || err)
}, 200)
export default {
  components: {
    NaviInput: () => import('@/components/NaviInput'),
  },
  apollo: {
    list: {
      query: gql`
        query($path: String!) {
          list(path: $path) {
            name
            path
            icon
            mtime
            type
            size
            atime
            isHidden
          }
        }
      `,
      variables() {
        return {
          path: this.path,
        }
      },
      error(error) {
        showError(error)
        this.goBack(false)
      },
      subscribeToMore: {
        document: gql`
          subscription($path: String!) {
            list(path: $path) {
              name
              path
              icon
              mtime
              type
              size
              atime
            }
          }
        `,
        // 传递给订阅的变量
        // 由于我们使用了函数，因此它们是响应式的
        variables() {
          return {
            path: this.path,
          }
        },
        // 变更之前的结果
        updateQuery: (
          previousResult,
          {
            subscriptionData: {
              data: { list },
            },
          }
        ) => {
          return {
            list,
          }
        },
        error(error) {
          showError(error)
        },
      },
    },
  },
  async asyncData({ $axios }) {
    return {
      os: os.platform(),
    }
  },
  data() {
    return {
      columns: [
        {
          title: '名称',
          dataIndex: 'name',
          scopedSlots: { customRender: 'name' },
        },
        {
          title: '类型',
          dataIndex: 'type',
          scopedSlots: { customRender: 'type' },
          width: 120,
        },
        {
          title: '大小',
          dataIndex: 'size',
          scopedSlots: { customRender: 'size' },
          width: 150,
        },
        {
          title: '修改日期',
          dataIndex: 'mtime',
          scopedSlots: { customRender: 'mtime' },
          width: 160,
        },
        {
          title: '创建日期',
          dataIndex: 'atime',
          scopedSlots: { customRender: 'atime' },
          width: 160,
        },
      ],
      upperPath: '',
      path: './',
      pathStack: [],
      pathStackIndex: 0,
      tableContentHeight: 500,
      searchKey: '',
    }
  },
  methods: {
    openPath(record) {
      if (record.type === 'dir') {
        this.gotoPath(record.path)
      } else {
        this.openFile(record.path)
      }
    },
    gotoPath(path, navi = false) {
      if (!navi) {
        this.pathStack.length = this.pathStackIndex + 1
        this.pathStack.push(path)
        this.pathStackIndex++
      }
      if (path.endsWith(':')) path += '\\'
      this.path = path
      this.getUpperPath()
    },
    goBack(navi = true) {
      if (this.pathStackIndex > 0) {
        this.gotoPath(this.pathStack[--this.pathStackIndex], true)
        if (!navi) {
          this.pathStack.pop()
        }
      }
    },
    goForward(navi = true) {
      if (this.pathStackIndex < this.pathStack.length - 1)
        this.gotoPath(this.pathStack[++this.pathStackIndex], true)
    },
    formatTime(time) {
      return moment(+time).format('YYYY-MM-DD HH:mm:ss')
    },
    formatSize(size) {
      return formatIO.size(+size).toUpperCase()
    },
    formatType(type) {
      switch (type) {
        case 'dir':
          return '文件夹'
        default:
          return `${type.substr(1).toUpperCase()} 文件`
      }
    },
    openFile(path) {
      this.$apollo.query({
        query: gql`
          query($path: String!) {
            openFile(path: $path)
          }
        `,
        variables: {
          path,
        },
        fetchPolicy: 'no-cache',
      })
    },
    handlePathInput(e) {
      this.gotoPath(e.target.value)
    },
    getTableContentHeight() {
      this.tableContentHeight = document.body.clientHeight - 56 - 54 - 4
    },
    async getFullPath(...paths) {
      const {
        data: { path },
      } = await this.$apollo.query({
        query: gql`
          query($paths: [String!]!) {
            path(paths: $paths)
          }
        `,
        variables: {
          paths,
        },
        fetchPolicy: 'no-cache',
      })
      return path
    },
    async getUpperPath() {
      this.upperPath = await this.getFullPath(this.path, '../')
    },
    gotoUpperPath() {
      if (this.upperPath !== this.path) this.gotoPath(this.upperPath)
    },
    refresh() {
      this.$apollo.queries.list.refetch()
    },
    clickPath(path) {
      if (path !== this.path) this.gotoPath(path)
    },
  },
  computed: {
    filterList() {
      return this.list
        ? this.list.filter((item) =>
            item.name.toUpperCase().includes(this.searchKey.toUpperCase())
          )
        : []
    },
  },
  async mounted() {
    this.getTableContentHeight()
    window.onresize = this.getTableContentHeight
    this.path = await this.getFullPath('./', './')
    this.getUpperPath()
    this.pathStack = [this.path]
  },
}
</script>
<style>
* {
  transition-duration: 0.5s;
}
</style>
<style lang="less" scoped>
.naviBar {
  padding: 12px;
  height: 56px;
  .icon {
    font-size: 18px;
    flex-shrink: 0;
    margin-right: 18px;
    &.disabled {
      opacity: 0.3;
      cursor: not-allowed;
    }
  }
  .pathInput {
    width: 100%;
    margin-right: 12px;
  }
  /deep/ .searchInput {
    width: 30%;
    max-width: 500px;
    flex-shrink: 0;
    input {
      height: 36px;
    }
  }
}
.content {
  height: calc(100% - 56px);
  overflow: auto;
  .filename {
    word-break: break-all;
    &.hidden {
      > .icon {
        opacity: 0.3;
      }
    }
    > .icon {
      width: 32px;
      height: 32px;
      margin-right: 5px;
    }
  }
}
</style>
